﻿#region Copyright
// Copyright (c) 2011-2012 RaisingForce Team (Alikin Sergey)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RaisingForce.Raise.Measures;

namespace RaisingForce.Raise.Tests
{


    /// <summary>
    ///Это класс теста для DistanceTest, в котором должны
    ///находиться все модульные тесты DistanceTest
    ///</summary>
    [TestClass()]
    public class DistanceTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Получает или устанавливает контекст теста, в котором предоставляются
        ///сведения о текущем тестовом запуске и обеспечивается его функциональность.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Дополнительные атрибуты теста
        // 
        //При написании тестов можно использовать следующие дополнительные атрибуты:
        //
        //ClassInitialize используется для выполнения кода до запуска первого теста в классе
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //ClassCleanup используется для выполнения кода после завершения работы всех тестов в классе
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //TestInitialize используется для выполнения кода перед запуском каждого теста
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //TestCleanup используется для выполнения кода после завершения каждого теста
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        [TestMethod]
        public void SerializationTest()
        {
            Distance target = new Distance(15, DistanceMeasures.Centimetre);
            SerializationHelper.Test(ref target);
            Distance expected = new Distance(15, DistanceMeasures.Centimetre);
            Assert.AreEqual(target, expected);
            target = Distance.Unknown;
            SerializationHelper.Test(ref target);
            expected = new Distance(0, DistanceMeasures.Millimetre);
            Assert.AreEqual(target, expected);
            expected = Distance.Unknown;
            Assert.AreEqual(target, expected);
        }

        /// <summary>
        ///Тест для Get
        ///</summary>
        [TestMethod()]
        public void GetTest()
        {
            // Unknown во всех измерениях
            Distance target = Distance.Unknown;
            Assert.IsTrue(target.IsUnknown);
            IDistanceMeasure measure = DistanceMeasures.Metre;
            double expected = Distance.UnknownValue;
            double actual;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Decimetre;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Centimetre;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Millimetre;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            target = new Distance();
            Assert.IsTrue(target.IsUnknown);
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            // 1 метр во всех измерениях
            target = new Distance(1.0d, DistanceMeasures.Metre);
            Assert.IsFalse(target.IsUnknown);
            measure = DistanceMeasures.Metre;
            expected = 1.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Decimetre;
            expected = 10.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Centimetre;
            expected = 100.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Millimetre;
            expected = 1000.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            // 15 дециметров во всех измерениях
            target = new Distance(15, DistanceMeasures.Decimetre);
            Assert.IsFalse(target.IsUnknown);
            measure = DistanceMeasures.Metre;
            expected = 1.5d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Decimetre;
            expected = 15.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Centimetre;
            expected = 150.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
            measure = DistanceMeasures.Millimetre;
            expected = 1500.0d;
            actual = target.Get(measure);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для CompareTo
        ///</summary>
        [TestMethod()]
        public void CompareToTest()
        {
            // Unknown == Unknown
            Distance target = new Distance();
            Distance other = Distance.Unknown;
            int expected = 0;
            int actual;
            actual = target.CompareTo(other);
            Assert.AreEqual(expected, actual);
            // Unknown < 15dm
            other = new Distance(15, DistanceMeasures.Decimetre);
            expected = -1;
            actual = target.CompareTo(other);
            Assert.AreEqual(expected, actual);
            // 1.5m == 15dm
            target = new Distance(1.5, DistanceMeasures.Metre);
            expected = 0;
            actual = target.CompareTo(other);
            Assert.AreEqual(expected, actual);
            // 149sm < 15dm
            target = new Distance(149, DistanceMeasures.Centimetre);
            expected = -1;
            actual = target.CompareTo(other);
            Assert.AreEqual(expected, actual);
            // 1501mm > 15dm
            target = new Distance(1501, DistanceMeasures.Millimetre);
            expected = 1;
            actual = target.CompareTo(other);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для Equals
        ///</summary>
        [TestMethod()]
        public void EqualsTest()
        {
            // 12sm != null
            Distance target = new Distance(12, DistanceMeasures.Centimetre);
            object obj = null;
            bool expected = false;
            bool actual;
            actual = target.Equals(obj);
            Assert.AreEqual(expected, actual);
            // 12sm == 120mm
            obj = new Distance(120, DistanceMeasures.Millimetre);
            expected = true;
            actual = target.Equals(obj);
            Assert.AreEqual(expected, actual);
            // 12sm != 121mm
            obj = new Distance(121, DistanceMeasures.Millimetre);
            expected = false;
            actual = target.Equals(obj);
            Assert.AreEqual(expected, actual);
            // 12sm != string
            obj = "abcd";
            expected = false;
            actual = target.Equals(obj);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для Equals
        ///</summary>
        [TestMethod()]
        public void EqualsTest1()
        {
            // 12cm == 120mm
            Distance target = new Distance(12, DistanceMeasures.Centimetre);
            Distance other = new Distance(120, DistanceMeasures.Millimetre);
            bool expected = true;
            bool actual;
            actual = target.Equals(other);
            Assert.AreEqual(expected, actual);
            // 12cm != 121mm
            other = new Distance(121, DistanceMeasures.Millimetre);
            expected = false;
            actual = target.Equals(other);
        }

        /// <summary>
        ///Тест для GetHashCode
        ///</summary>
        [TestMethod()]
        public void GetHashCodeTest()
        {
            // Unknown == Unknown
            Distance target = Distance.Unknown;
            int expected = Distance.Unknown.GetHashCode();
            int actual;
            actual = target.GetHashCode();
            Assert.AreEqual(expected, actual);
            // 1.2m == 120cm
            target = new Distance(1.2, DistanceMeasures.Metre);
            expected = new Distance(120, DistanceMeasures.Centimetre).GetHashCode();
            actual = target.GetHashCode();
            Assert.AreEqual(expected, actual);
            // 1.2m != 121cm
            expected = new Distance(121, DistanceMeasures.Centimetre).GetHashCode();
            actual = target.GetHashCode();
            Assert.AreNotEqual(expected, actual);
        }

        /// <summary>
        ///Тест для ToString
        ///</summary>
        [TestMethod()]
        public void ToStringTest()
        {
            // Unknown.ToString() == UnknownString
            Distance target = Distance.Unknown;
            string expected = Distance.UnknownString;
            string actual;
            actual = target.ToString();
            Assert.AreEqual(expected, actual);
            // 12cm.ToString() == 1.2dm.ToString() == "1,2 дм"
            target = new Distance(12, DistanceMeasures.Centimetre);
            expected = new Distance(1.2, DistanceMeasures.Decimetre).ToString();
            actual = target.ToString();
            Assert.AreEqual(expected, actual);
            expected = string.Format("{0:F1} {1}", 1.2d, DistanceMeasures.Decimetre.ShortName);
            actual = target.ToString();
            Assert.AreEqual(expected, actual);
            // 0.5cm.ToString() == 5mm.ToString() == "5,0 мм"
            target = new Distance(0.5, DistanceMeasures.Centimetre);
            expected = new Distance(5, DistanceMeasures.Millimetre).ToString();
            actual = target.ToString();
            Assert.AreEqual(expected, actual);
            expected = string.Format("{0:F1} {1}", 5.0d, DistanceMeasures.Millimetre.ShortName);
            actual = target.ToString();
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для ValueIsValid
        ///</summary>
        [TestMethod()]
        public void ValueIsValidTest()
        {
            // Unknown - valid
            double measureValue = Distance.UnknownValue;
            bool expected = true;
            bool actual;
            actual = Distance.ValueIsValid(measureValue);
            Assert.AreEqual(expected, actual);
            // 0.1 - valid
            measureValue = 0.1;
            expected = true;
            actual = Distance.ValueIsValid(measureValue);
            // 231 - valid
            measureValue = 231;
            expected = true;
            actual = Distance.ValueIsValid(measureValue);
            // -1 - invalid
            measureValue = -1;
            expected = false;
            actual = Distance.ValueIsValid(measureValue);
        }

        /// <summary>
        ///Тест для op_Addition
        ///</summary>
        [TestMethod()]
        public void op_AdditionTest()
        {
            // 1dm + 2cm = 1.2dm
            Distance first = new Distance(1, DistanceMeasures.Decimetre);
            Distance second = new Distance(2, DistanceMeasures.Centimetre);
            Distance expected = new Distance(1.2, DistanceMeasures.Decimetre);
            Distance actual;
            actual = (first + second);
            Assert.AreEqual(expected, actual);
            actual = second + first;
            Assert.AreEqual(expected, actual);
            // 2cm + Unknown = Unknown
            first = Distance.DefineInCentimetre(2);
            second = Distance.Unknown;
            expected = Distance.Unknown;
            actual = (first + second);
            Assert.AreEqual(expected, actual);
            actual = (second + first);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Division
        ///</summary>
        [TestMethod()]
        public void op_DivisionTest()
        {
            // 0.5m / 2dm = 25dm
            Distance first = new Distance(0.5, DistanceMeasures.Metre);
            Distance second = new Distance(2, DistanceMeasures.Decimetre);
            Distance expected = new Distance(25, DistanceMeasures.Decimetre);
            Distance actual;
            actual = (first / second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Equality
        ///</summary>
        [TestMethod()]
        public void op_EqualityTest()
        {
            // 0.2m == 200mm
            Distance first = new Distance(0.2, DistanceMeasures.Metre);
            Distance second = new Distance(200, DistanceMeasures.Millimetre);
            bool expected = true;
            bool actual;
            actual = (first == second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first != second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_GreaterThan
        ///</summary>
        [TestMethod()]
        public void op_GreaterThanTest()
        {
            // 0.2m > 199mm
            Distance first = new Distance(0.2, DistanceMeasures.Metre);
            Distance second = new Distance(199, DistanceMeasures.Millimetre);
            bool expected = true;
            bool actual;
            actual = (first > second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first <= second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_GreaterThanOrEqual
        ///</summary>
        [TestMethod()]
        public void op_GreaterThanOrEqualTest()
        {
            // 0.2m >= 199mm
            Distance first = new Distance(0.2, DistanceMeasures.Metre);
            Distance second = new Distance(199, DistanceMeasures.Millimetre);
            bool expected = true;
            bool actual;
            actual = (first >= second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first < second);
            Assert.AreEqual(expected, actual);
            // 0.2m >= 200mm
            second = new Distance(200, DistanceMeasures.Millimetre);
            expected = true;
            actual = (first >= second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first < second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Inequality
        ///</summary>
        [TestMethod()]
        public void op_InequalityTest()
        {
            // 0.2m != 19.9cm
            Distance first = new Distance(0.2, DistanceMeasures.Metre);
            Distance second = new Distance(19.9, DistanceMeasures.Centimetre);
            bool expected = true;
            bool actual;
            actual = (first != second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first == second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_LessThan
        ///</summary>
        [TestMethod()]
        public void op_LessThanTest()
        {
            // 1dm < 1m
            Distance first = new Distance(1, DistanceMeasures.Decimetre);
            Distance second = new Distance(1, DistanceMeasures.Metre);
            bool expected = true;
            bool actual;
            actual = (first < second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first >= second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_LessThanOrEqual
        ///</summary>
        [TestMethod()]
        public void op_LessThanOrEqualTest()
        {
            // 1dm < 1m
            Distance first = new Distance(1, DistanceMeasures.Decimetre);
            Distance second = new Distance(1, DistanceMeasures.Metre);
            bool expected = true;
            bool actual;
            actual = (first <= second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first > second);
            Assert.AreEqual(expected, actual);
            // 1m <= 1m
            first = new Distance(1, DistanceMeasures.Metre);
            second = new Distance(1, DistanceMeasures.Metre);
            expected = true;
            actual = (first <= second);
            Assert.AreEqual(expected, actual);
            expected = false;
            actual = (first > second);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Multiply
        ///</summary>
        [TestMethod()]
        public void op_MultiplyTest()
        {
            // 2cm * 3dm == 6mm
            Distance first = new Distance(2, DistanceMeasures.Centimetre);
            Distance second = new Distance(3, DistanceMeasures.Decimetre);
            Distance expected = new Distance(6, DistanceMeasures.Millimetre);
            Distance actual;
            actual = (first * second);
            Assert.AreEqual(expected, actual);
            actual = (second * first);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Subtraction
        ///</summary>
        [TestMethod()]
        public void op_SubtractionTest()
        {
            // 2cm - 3dm
            Distance first = new Distance(2, DistanceMeasures.Centimetre);
            Distance second = new Distance(3, DistanceMeasures.Decimetre);
            Distance expected = new Distance(28, DistanceMeasures.Centimetre);
            Distance actual;
            actual = (first - second);
            Assert.AreEqual(expected, actual);
            actual = (second - first);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void OpAssignmentTest()
        {
            Distance distance1 = new Distance(2, DistanceMeasures.Centimetre);
            Distance distance2 = distance1;
            Assert.IsTrue(distance1 == distance2);
            Assert.IsFalse(distance1 != distance2);
        }

        /// <summary>
        ///Тест для op_Division
        ///</summary>
        [TestMethod()]
        public void op_DivisionTest1()
        {
            // 6cm / 3 = 20mm
            Distance distance = new Distance(6, DistanceMeasures.Centimetre);
            double divisor = 3.0d;
            Distance expected = new Distance(20, DistanceMeasures.Millimetre);
            Distance actual;
            actual = (distance / divisor);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Multiply
        ///</summary>
        [TestMethod()]
        public void op_MultiplyTest1()
        {
            // 2 * 5mm = 1cm
            double multiplier = 2.0d;
            Distance distance = new Distance(5, DistanceMeasures.Millimetre);
            Distance expected = new Distance(1, DistanceMeasures.Centimetre);
            Distance actual;
            actual = (multiplier * distance);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///Тест для op_Multiply
        ///</summary>
        [TestMethod()]
        public void op_MultiplyTest2()
        {
            // 5dm * 2 = 1m
            Distance distance = new Distance(5, DistanceMeasures.Decimetre); 
            double multiplier = 2.0d; 
            Distance expected = new Distance(1, DistanceMeasures.Metre);
            Distance actual;
            actual = (distance * multiplier);
            Assert.AreEqual(expected, actual);
        }
    }
}
